#include <my_header.h>

typedef struct share_value_s
{
    int flag_A;
    int flag_B;
    int flag_C;
    int flag_D;
    pthread_mutex_t mLock;
    pthread_cond_t cond_A_B;
    pthread_cond_t cond_B_D;
    pthread_cond_t cond_C_D;
    pthread_cond_t cond_D_E;
}share_value_t;

void * threadFuncA(void * arg);
void * threadFuncB(void * arg);
void * threadFuncC(void * arg);
void * threadFuncD(void * arg);
void * threadFuncE(void * arg);

void funcA();
void funcB();
void funcC();
void funcD();
void funcE();
/* usage */
int main(int argc, char *argv[])
{
    ARGS_CHECK(argc,1);
    share_value_t share_value;
    share_value.flag_A = 0;
    share_value.flag_B = 0;
    share_value.flag_C = 0;
    share_value.flag_D = 0;
    pthread_mutex_init(&share_value.mLock,NULL);
    pthread_cond_init(&share_value.cond_A_B,NULL);
    pthread_cond_init(&share_value.cond_B_D,NULL);
    pthread_cond_init(&share_value.cond_C_D,NULL);
    pthread_cond_init(&share_value.cond_D_E,NULL);

    pthread_t tid[5];
    int ret_create1 = pthread_create(&tid[0],NULL,threadFuncA,&share_value);
    THREAD_ERROR_CHECK(ret_create1,"pthread_create1");
    int ret_create2 = pthread_create(&tid[1],NULL,threadFuncB,&share_value);
    THREAD_ERROR_CHECK(ret_create2,"pthread_create2");
    int ret_create3 = pthread_create(&tid[2],NULL,threadFuncC,&share_value);
    THREAD_ERROR_CHECK(ret_create3,"pthread_create3");
    int ret_create4 = pthread_create(&tid[3],NULL,threadFuncD,&share_value);
    THREAD_ERROR_CHECK(ret_create4,"pthread_create4");
    int ret_create5 = pthread_create(&tid[4],NULL,threadFuncE,&share_value);
    THREAD_ERROR_CHECK(ret_create5,"pthread_create5");

    for(int i = 0;i<5;i++)
    {
        pthread_join(tid[i],NULL);
    }
    return 0;
}

void funcA(){
    printf("Hello,I am A.\n");
}
void funcB(){
    printf("Hello,I am B.\n");
}
void funcC(){
    printf("Hello,I am C.\n");
}
void funcD(){
    printf("Hello,I am D.\n");
}
void funcE(){
    printf("Hello,I am E.\n");
}

void * threadFuncA(void * arg)
{
    share_value_t *pshare_value = (share_value_t *)arg;

    pthread_mutex_lock(&pshare_value->mLock);
    pshare_value->flag_A = 1;
    funcA();
    pthread_cond_signal(&pshare_value->cond_A_B);
    pthread_mutex_unlock(&pshare_value->mLock);

    pthread_exit(NULL);
}

void * threadFuncB(void * arg)
{
    share_value_t *pshare_value = (share_value_t *)arg;
    pthread_mutex_lock(&pshare_value->mLock);
    while(pshare_value->flag_A != 1)
    {
        pthread_cond_wait(&pshare_value->cond_A_B,&pshare_value->mLock);
    }
    funcB();
    pshare_value->flag_B = 1;
    pthread_cond_signal(&pshare_value->cond_B_D);
    pthread_mutex_unlock(&pshare_value->mLock);
    pthread_exit(NULL);
}

void * threadFuncC(void * arg)
{
    share_value_t *pshare_value = (share_value_t *)arg;

    pthread_mutex_lock(&pshare_value->mLock);
    funcC();
    pshare_value->flag_C = 1;
    pthread_cond_signal(&pshare_value->cond_C_D);
    pthread_mutex_unlock(&pshare_value->mLock);

    pthread_exit(NULL);
}

void * threadFuncD(void * arg)
{
    share_value_t *pshare_value = (share_value_t *)arg;
    pthread_mutex_lock(&pshare_value->mLock);
    while(pshare_value->flag_B !=1||pshare_value->flag_C != 1)
    {
        if(pshare_value->flag_B != 1)
        {
            pthread_cond_wait(&pshare_value->cond_B_D,&pshare_value->mLock);
        }
        if(pshare_value->flag_C != 1)
        {
            pthread_cond_wait(&pshare_value->cond_C_D,&pshare_value->mLock);
        }
    }
    funcD();
    pshare_value->flag_D = 1;
    pthread_cond_signal(&pshare_value->cond_D_E);
    pthread_mutex_unlock(&pshare_value->mLock);

    pthread_exit(NULL);
}

void * threadFuncE(void * arg)
{
    share_value_t *pshare_value = (share_value_t *)arg;
    pthread_mutex_lock(&pshare_value->mLock);
    while(pshare_value->flag_D != 1)
    {
        pthread_cond_wait(&pshare_value->cond_D_E,&pshare_value->mLock);
    }
    funcE();
    pthread_mutex_unlock(&pshare_value->mLock);
    pthread_exit(NULL);
}
